5.2-Service Worker
Create by fall on 22 Nov 2020
Recently revised in 28 Jul 2025
Service Worker
Service Worker 旨在创建有效的离线体验。可以使你的应用先访问本地缓存资源,所以在离线状态时,在没有通过网络接收到更多的数据前,仍可以提供基本的功能
Service Worker 可以拦截当前网站所有的请求,进行判断(需要编写相应的判断程序),如果需要向服务器发
service Worker 脱离于主线程之外的线程,用于解决性能问题,一些消耗时间,并且复杂的计算通过 service Worker 进行计算。
service worker 的特点
- 独立的线程,有自己的 worker content,不能和主线程直接通信,必须通过消息完成。
- 不能使用诸如
alert()
和confirm()
方法 - 一旦被 install 就会一直存在,除非被 uninstall
- 不需要时,会进行休眠
- 可以拦截代理请求和返回,缓存的文件可以被读取到
- 离线的内容,开发者可控
- 可以向客户端推送信息
- 分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
- 不能直接操作 DOM
- 不能操作本地磁盘中的数据
- 必须是 https 协议,或者是 localhost 环境下才能工作
分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
使用步骤
- service worker URL 通过
serviceWorkerContainer.register()
用于获取和注册 - 注册成功,service worker 就在
ServiceWorkerGlobalScope
环境中运行,该环境与主线程独立,同时没有访问 DOM 的能力 - 可以进行处理事件
- service worker 控制的页面打开后会尝试去安装 service worker,最先发送给 service worker 的事件是安装事件(在该事件内可以开始进行填充 IndexDB 和缓存站点资源),让所有资源可以离线访问。
- oninstall 事件处理程序执行完成之后,就可以认为 service worker 已经安装完成了
- 然后是激活,service worker 安装完成之后,会收到激活事件。
onactivate
主要用途是清理先前版本的 service worker 脚本中使用的资源。 - Service Worker 现在可以控制页面,但仅在
register()
成功后打开的页面,也就是说,页面起始于有没有 service worker 并且在接下来的生命周期维持这个状态,所以不得不重新加载让 service worker 重新获得控制。
支持的事件
install
、activate
、message
、fetch
、sync
、push
注册 service worker
if('serviceWorker' in navigator){ // 确保浏览器支持 service worker
// 注册站点的 service worker
// 路径为相对于 origin 的文件路径,如 https://mdn.github.io/sw-test/sw.js 引入应该为 /sw-test/sw.js
// scope 为选填的内容
navigator.serviceWorker.register('/sw-test/sw.js',{scope:'/sw-test/'}).then(function(reg){
// worked
console.log('成功')
}).catch(function(error){
// failed
console.log('Registration failed with '+ error)
})
}
单个 service worker 可以控制很多页面,每个 scope 里的页面加载完的时候,安装在页面的 service worker 可以控制它,小心 service worker 中的全局变量,每个页面不会有自己独有的 worker。
安装和激活
this.addEventListener('install',function(event){
event.waitUntil(
caches.open('v1').then(function(cache){
return cache.addAll([
'/sw-test/',
'/sw-test/index.html',
'/sw-test/style.css',
'/sw-test/app.js',
'/sw-test/star-wars-logo.jpg',
])
})
)
})
localStorage 它是同步的,不允许在 service workers 内使用。
现在已经有了站点内容的缓存,你可以通过 fetch 事件告诉 service worker 让它用这些缓存内容。
所有被 service woker 控制的资源每次被请求到时,都会触发 fetch
事件吗